package cn.edu.sgu.www.mhxysy.service.xingyin.impl;

import cn.edu.sgu.www.mhxysy.consts.CustomMessages;
import cn.edu.sgu.www.mhxysy.dto.xingyin.XingyinAttributeDTO;
import cn.edu.sgu.www.mhxysy.entity.except.Property;
import cn.edu.sgu.www.mhxysy.entity.xingyin.Xingyin;
import cn.edu.sgu.www.mhxysy.entity.xingyin.XingyinAttribute;
import cn.edu.sgu.www.mhxysy.enums.PropertyTypes;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.mapper.except.PropertyMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingyin.XingyinAttributeMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingyin.XingyinMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingyin.XingyinViewAttributeMapper;
import cn.edu.sgu.www.mhxysy.observer.impl.AdvancedPropertyObserver;
import cn.edu.sgu.www.mhxysy.pager.Pager;
import cn.edu.sgu.www.mhxysy.pager.xingyin.XingyinAttributePager;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.service.xingyin.XingyinAttributeService;
import cn.edu.sgu.www.mhxysy.util.ObjectUtils;
import cn.edu.sgu.www.mhxysy.util.StringUtils;
import cn.edu.sgu.www.mhxysy.vo.except.AttributeVO;
import cn.edu.sgu.www.mhxysy.vo.xingyin.XingyinViewAttributeVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Service
public class XingyinAttributeServiceImpl implements XingyinAttributeService {

    private final XingyinMapper xingyinMapper;
    private final PropertyMapper propertyMapper;
    private final XingyinAttributeMapper xingyinAttributeMapper;
    private final XingyinViewAttributeMapper xingyinViewAttributeMapper;
    private final AdvancedPropertyObserver advancedPropertyObserver;

    @Autowired
    public XingyinAttributeServiceImpl(
            XingyinMapper xingyinMapper,
            PropertyMapper propertyMapper,
            XingyinAttributeMapper xingyinAttributeMapper,
            XingyinViewAttributeMapper xingyinViewAttributeMapper,
            AdvancedPropertyObserver advancedPropertyObserver) {
        this.xingyinMapper = xingyinMapper;
        this.propertyMapper = propertyMapper;
        this.xingyinAttributeMapper = xingyinAttributeMapper;
        this.xingyinViewAttributeMapper = xingyinViewAttributeMapper;
        this.advancedPropertyObserver = advancedPropertyObserver;
    }

    @Override
    public void insert(XingyinAttributeDTO xingyinAttributeDTO) {
        xingyinAttributeDTO.setId(null);

        XingyinAttribute xingyinAttribute = toEntity(xingyinAttributeDTO);

        xingyinAttribute.setId(xingyinAttribute.uuid());

        int update = xingyinAttributeMapper.insert(xingyinAttribute);

        if (update > 0) {
            Property property = propertyMapper.selectById(xingyinAttribute.getPropertyId());

            // 添加星印高级属性，更新角色高级属性缓存
            if (PropertyTypes.GJSX.getValue().equals(property.getType())) {
                Xingyin xingyin = xingyinMapper.selectById(xingyinAttribute.getXingyinId());

                advancedPropertyObserver.update(xingyin.getRoleId());
            }
        }
    }

    @Override
    public void deleteById(String id) {
        XingyinAttribute xingyinAttribute = xingyinAttributeMapper.selectById(id);

        if (xingyinAttribute == null) {
            throw new GlobalException(ResponseCode.NOT_FOUND, "删除失败，数据不存在。");
        }

        int update = xingyinAttributeMapper.deleteById(id);

        if (update > 0) {
            Property property = propertyMapper.selectById(xingyinAttribute.getPropertyId());

            // 修改星印高级属性，更新角色高级属性缓存
            if (PropertyTypes.GJSX.getValue().equals(property.getType())) {
                Xingyin xingyin = xingyinMapper.selectById(xingyinAttribute.getXingyinId());

                advancedPropertyObserver.update(xingyin.getRoleId());
            }
        }
    }

    @Override
    public void updateById(XingyinAttributeDTO xingyinAttributeDTO) {
        ObjectUtils.requireNonNull(xingyinAttributeDTO.getId(), CustomMessages.ID_NOT_NULL);

        XingyinAttribute xingyinAttribute = toEntity(xingyinAttributeDTO);

        int update = xingyinAttributeMapper.updateById(xingyinAttribute);

        if (update > 0) {
            Integer propertyId = xingyinAttribute.getPropertyId();

            if (propertyId != null) {
                Property property = propertyMapper.selectById(propertyId);

                // 修改星印高级属性，更新角色高级属性缓存
                if (PropertyTypes.GJSX.getValue().equals(property.getType())) {
                    Xingyin xingyin = xingyinMapper.selectById(xingyinAttribute.getXingyinId());

                    advancedPropertyObserver.update(xingyin.getRoleId());
                }
            }
        }
    }

    @Override
    public List<AttributeVO> selectAttributes(String xingyinId) {
        return xingyinAttributeMapper.selectAttributes(xingyinId);
    }

    @Override
    public Page<XingyinAttribute> selectByPage(XingyinAttributePager pager) {
        QueryWrapper<XingyinAttribute> queryWrapper = new QueryWrapper<>();
        Page<XingyinAttribute> page = Pager.ofPage(pager);

        queryWrapper.eq(
                StringUtils.isNotEmpty(pager.getXingyinId()),
                "xingyin_id", pager.getXingyinId()
        );

        return xingyinAttributeMapper.selectPage(page, queryWrapper);
    }

    private XingyinAttribute toEntity(XingyinAttributeDTO xingyinAttributeDTO) {
        boolean result = validateRange(xingyinAttributeDTO);

        XingyinAttribute xingyinAttribute = new XingyinAttribute();

        if (result) {
            xingyinAttribute.setId(xingyinAttributeDTO.getId());
            xingyinAttribute.setType(xingyinAttributeDTO.getType());
            xingyinAttribute.setXingyinId(xingyinAttributeDTO.getXingyinId());
            xingyinAttribute.setPropertyId(xingyinAttributeDTO.getPropertyId());
            xingyinAttribute.setPropertyValue(xingyinAttributeDTO.getPropertyValue());
        }

        return xingyinAttribute;
    }

    /**
     * 验证星印属性值
     * @param xingyinAttributeDTO 属性属性信息
     * @return 验证通过返回true，否则返回false
     */
    private boolean validateRange(XingyinAttributeDTO xingyinAttributeDTO) {
        // 验证星印属性条数，星印最多拥有4条属性（1条主属性、3条鉴定属性）
        QueryWrapper<XingyinAttribute> queryWrapper = new QueryWrapper<>();

        queryWrapper.ne(
                StringUtils.isNotEmpty(xingyinAttributeDTO.getId()),
                "id", xingyinAttributeDTO.getId()
        );
        queryWrapper.eq("xingyin_id", xingyinAttributeDTO.getXingyinId());

        Long count = xingyinAttributeMapper.selectCount(queryWrapper);

        if (count >= 4) {
            throw new GlobalException(ResponseCode.FORBIDDEN, "星印属性条数已达上限。");
        }

        // 构建查询条件
        Map<String, Object> hashMap = new HashMap<>();

        hashMap.put("type", xingyinAttributeDTO.getType());
        hashMap.put("xingyinId", xingyinAttributeDTO.getXingyinId());
        hashMap.put("propertyId", xingyinAttributeDTO.getPropertyId());

        // 获取查询结果
        XingyinViewAttributeVO viewAttribute = xingyinViewAttributeMapper.selectAttribute(hashMap);

        if (viewAttribute == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "非法的星印属性。");
        }

        // 得到最大值、最小值
        Integer min = viewAttribute.getMin();
        Integer max = viewAttribute.getMax();
        // 得到星印属性值
        Integer value = xingyinAttributeDTO.getPropertyValue();

        // 属性值不在[min, max]，抛出异常
        if (value > max || value < min) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "属性值不合法，数值范围为：" + min + "~" + max);
        }

        return true;
    }

}